#ifndef __BFCP__
#define __BFCP__

#include <memory>
#include "rutil/ThreadIf.hxx"
#include "rutil/Fifo.hxx"
#include "rutil/ProducerFifoBuffer.hxx"
#include "rutil/ConsumerFifoBuffer.hxx"
#include "zkbfcp/BfcpStack.hxx"
#include "zkbfcp/BfcpMessage.hxx"

class BfcpParticipantKey
{
public:
    BfcpParticipantKey();
    BfcpParticipantKey(UInt32 confId, UInt16 userId);
    BfcpParticipantKey(const BfcpParticipantKey& rhs);
    BfcpParticipantKey operator=(const BfcpParticipantKey& rhs);

    bool operator<(const BfcpParticipantKey& rhs) const;

    UInt32 getConferenceId() const { return mConfId; }
    UInt16 getUserId() const { return mUserId; }

private:
    UInt32 mConfId;
    UInt16 mUserId;

    friend EncodeStream& operator<<(EncodeStream& strm, const BfcpParticipantKey& key);
};


class BFCPClient : public bfcp::BfcpStack, public resip::ThreadIf
{
public:
    BFCPClient(resip::Fifo<bfcp::BfcpTransactionMessage>& rxFifo, UInt32 confId, UInt16 userId);
    BFCPClient(UInt32 confId, UInt16 userId, const resip::Data& printableAddress, int port, resip::TransportType type = resip::UDP);
    ~BFCPClient();

    void run();
    void shutdown();

    void thread();

    std::shared_ptr<resip::ConsumerFifoBuffer<bfcp::BfcpTransactionMessage> > getConsumerFifo();

    std::auto_ptr<bfcp::BfcpMessage> requestHello();
    std::auto_ptr<bfcp::BfcpMessage> requestGoodbye();
    std::auto_ptr<bfcp::BfcpMessage> responseFloorStatusAck(const bfcp::BfcpMessage* req);
    std::auto_ptr<bfcp::BfcpMessage> responseGoodbyeAck(const bfcp::BfcpMessage* req);

protected:
    void processIncoming(bfcp::BfcpTransactionMessage* msg);

private:
    resip::Fifo<bfcp::BfcpTransactionMessage> mFifo;
    resip::ProducerFifoBuffer<bfcp::BfcpTransactionMessage> mBFCPMessages; // passed in
    bfcp::BfcpNetTuple mTarget;
    BfcpParticipantKey mKey;
    UInt64 mLastPingTime;
};

#endif // #ifndef __BFCP__
